package com.kyivmohyla.kma2.server;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.kyivmohyla.kma2.MailSender;
import com.kyivmohyla.kma2.client.UserService;
import com.kyivmohyla.kma2.client.exception.DelistedException;
import com.kyivmohyla.kma2.client.utils.MD5Hasher;
import com.kyivmohyla.kma2.client.utils.PasswordGenerator;
import com.kyivmohyla.kma2.dao.*;
import com.kyivmohyla.kma2.factory.DAOFactory;
import com.kyivmohyla.kma2.factory.SpringBeansFactory;
import com.kyivmohyla.kma2.model.*;
import com.kyivmohyla.kma2.server.proxy.Proxy;
import com.kyivmohyla.kma2.shared.model.*;
import org.springframework.dao.DataAccessException;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


//TODO вам не здається що цей класс робить занадто багато ?
public class UserServiceImpl extends RemoteServiceServlet implements UserService {

    private static final DAOFactory factory = (DAOFactory) SpringBeansFactory.getInstance().getBeanByName("oracleDaoFactory");

    @Override
    public void changePassword(String email) throws DelistedException {
        Staff staff;
        try {
            staff = ((StaffDao) factory.getStaffDao()).getByEmail(email);
            String newPassword = PasswordGenerator.getInstance().getGeneratedPassword();
            String newPasswordHashed = MD5Hasher.getInstance().getHash(newPassword);
            staff.setPassword(newPasswordHashed);
            factory.getStaffDao().update(staff);
            MailSender.getInstance().sendMail(email, "Password Reset", "Hi " + email + ",<br>Your password was changed to " + newPassword);
        } catch (DataAccessException e) {
            throw new DelistedException("No user with such e-mail");
        }
    }

    @Override
    public void sendMail(String recipient, String subject, String message) {
        MailSender.getInstance().sendMail(recipient, subject, message);
    }

    @Override
    public void updateEquipment(UIEquipment equipment) throws DelistedException {
        try {
            factory.getEquipmentDao().update(Proxy.createFromUIEquipment(equipment));
        } catch (DataAccessException e) {
            throw new DelistedException(e.getMessage());
        }
    }

    @Override
    public void updateService(UIService service) throws DelistedException {
        try {
            factory.getServiceDao().update(Proxy.createFromUIService(service));
        } catch (DataAccessException e) {
            throw new DelistedException(e.getMessage());
        }
    }

    @Override
    public void deleteOrderServEquipByOrderId(int id) throws DelistedException {
        try {
            ((OrderServEquipDao) factory.getOrderServEquipDao()).deleteOrderServEquipByOrderId(id);
        } catch (DataAccessException e) {
            throw new DelistedException(e.getMessage());
        }
    }

    @Override
    public List<UIOrder> getOrdersByState(int[] states) {
        List<UIOrder> uiOrders = new ArrayList<UIOrder>();
        for (Order order : ((OrderDao) factory.getOrderDao()).getOrdersByState(states)) {
            uiOrders.add(Proxy.createFromOrder(order));
        }
        return uiOrders;
    }

    @Override
    public List<UIOrder> getOrdersByStateAndDate(int[] states, String date) {
        List<UIOrder> uiOrders = new ArrayList<UIOrder>();
        for (Order order : ((OrderDao) factory.getOrderDao()).getOrdersByStateAndDate(states, date)) {
            uiOrders.add(Proxy.createFromOrder(order));
        }
        return uiOrders;
    }

    @Override
    public List<UIOrder> getOrdersByStateAndDateAndPosition(int[] states, String date, int position) {
        List<UIOrder> uiOrders = new ArrayList<UIOrder>();
        for (Order order : ((OrderDao) factory.getOrderDao()).getOrdersByStateAndDateAndPosition(states, date, position)) {
            uiOrders.add(Proxy.createFromOrder(order));
        }
        return uiOrders;
    }

    @Override
    public List<UICustomer> getCustomerAllCustomers() {
        List<UICustomer> uiCustomers = new ArrayList<UICustomer>();
        for (Customer customer : factory.getCustomerDao().getAll()) {
            uiCustomers.add(Proxy.createFromCustomer(customer));
        }
        return uiCustomers;
    }

    @Override
    public List<UIEquipment> getEquipmentAllEquipment() {
        List<UIEquipment> uiEquipments = new ArrayList<UIEquipment>();
        for (Equipment equipment : factory.getEquipmentDao().getAll()) {
            uiEquipments.add(Proxy.createFromEquipment(equipment));
        }
        return uiEquipments;
    }

    @Override
    public List<UIHistory> getHistoryAllHistory() {
        List<UIHistory> uiHistories = new ArrayList<UIHistory>();
        for (History history : factory.getHistoryDao().getAll()) {
            uiHistories.add(Proxy.createFromHistory(history));
        }
        return uiHistories;
    }

    @Override
    public List<UIOrder> getOrderAllOrder() {
        List<UIOrder> uiOrders = new ArrayList<UIOrder>();
        for (Order order : factory.getOrderDao().getAll()) {
            uiOrders.add(Proxy.createFromOrder(order));
        }
        return uiOrders;
    }

    @Override
    public List<UIOrderServEquip> getOrderServEquipAllOrderServEquip() {
        List<UIOrderServEquip> uiOrderServEquips = new ArrayList<UIOrderServEquip>();
        for (OrderServEquip orderServEquip : factory.getOrderServEquipDao().getAll()) {
            uiOrderServEquips.add(Proxy.createFromOrderServEquip(orderServEquip));
        }
        return uiOrderServEquips;
    }

    @Override
    public List<UIPosition> getPositionAllPosition() {
        List<UIPosition> uiPositions = new ArrayList<UIPosition>();
        for (Position position : factory.getPositionDao().getAll()) {
            uiPositions.add(Proxy.createFromPosition(position));
        }
        return uiPositions;
    }

    @Override
    public List<UIRefs> getRefsAllRefs() {
        List<UIRefs> uiRefs = new ArrayList<UIRefs>();
        for (Refs refs : factory.getRefsDao().getAll()) {
            uiRefs.add(Proxy.createFromRefs(refs));
        }
        return uiRefs;
    }

    @Override
    public List<UIService> getServiceAllService() {
        List<UIService> uiServices = new ArrayList<UIService>();
        for (Service service : factory.getServiceDao().getAll()) {
            uiServices.add(Proxy.createFromService(service));
        }
        return uiServices;
    }

    @Override
    public List<UIService> getServiceByOrderId(int id) throws DelistedException {
        List<UIService> uiServices = new ArrayList<UIService>();
        for (Service service : ((ServiceDao) factory.getServiceDao()).getServiceByOrderId(id)) {
            uiServices.add(Proxy.createFromService(service));
        }
        return uiServices;
    }

    @Override
    public List<UIEquipment> getEquipmentByOrderId(int id) throws DelistedException {
        List<UIEquipment> uiEquipments = new ArrayList<UIEquipment>();
        for (Equipment equipment : ((EquipmentDao) factory.getEquipmentDao()).getEquipmentByOrderId(id)) {
            uiEquipments.add(Proxy.createFromEquipment(equipment));
        }
        return uiEquipments;
    }

    @Override
    public List<UIStaff> getStaffAllStaffs() {
        List<UIStaff> uiStaffs = new ArrayList<UIStaff>();
        for (Staff staff : factory.getStaffDao().getAll()) {
            uiStaffs.add(Proxy.createFromStaff(staff));
        }
        return uiStaffs;
    }

    @Override
    public List<UIStaff> getAllEngineers() {
        List<UIStaff> engineers = new ArrayList<UIStaff>();
        for (Staff engineer : ((StaffDao) factory.getStaffDao()).getAllEngineers()) {
            engineers.add(Proxy.createFromStaff(engineer));
        }
        return engineers;
    }

    @Override
    public List<UIState> getStateAllState() {
        List<UIState> uiStates = new ArrayList<UIState>();
        for (State state : factory.getStateDao().getAll()) {
            uiStates.add(Proxy.createFromState(state));
        }
        return uiStates;
    }

    @Override
    public UICustomer getCustomerById(int id) throws DelistedException {
        Customer customer;
        try {
            customer = factory.getCustomerDao().getById(id);
        } catch (DataAccessException e) {
            throw new DelistedException("No customer with such ID");
        }
        return Proxy.createFromCustomer(customer);
    }

    @Override
    public UICustomer getCustomerWithMaxId() throws DelistedException {
        UICustomer uiCustomer;
        try {
            uiCustomer = Proxy.createFromCustomer(((CustomerDao) factory.getCustomerDao()).getCustomerWithMaxId());
        } catch (DataAccessException e) {
            throw new DelistedException("Something went wrong");
        }
        return uiCustomer;
    }

    @Override
    public UIOrder getOrderWithMaxId() throws DelistedException {
        UIOrder uiOrder;
        try {
            uiOrder = Proxy.createFromOrder(((OrderDao) factory.getOrderDao()).getOrderWithMaxId());
        } catch (DataAccessException e) {
            throw new DelistedException(e.getMessage());
        }
        return uiOrder;
    }

    @Override
    public void addCustomer(UICustomer customer) throws DelistedException {
        try {
            factory.getCustomerDao().create(Proxy.createFromUICustomer(customer));
        } catch (DataAccessException e) {
            throw new DelistedException("No connection to the Database. Can not add Customer");
        }
    }

    @Override
    public void updateCustomer(UICustomer customer) throws DelistedException {
        try {
            factory.getCustomerDao().update(Proxy.createFromUICustomer(customer));
        } catch (DataAccessException e) {
            throw new DelistedException("No connection to the Database. Can not update Customer");
        }
    }

    @Override
    public void addOrder(UIOrder order) throws DelistedException {
        try {
            factory.getOrderDao().create(Proxy.createFromUIOrder(order));
        } catch (DataAccessException e) {
            throw new DelistedException(e.getMessage());
        }
    }

    @Override
    public void updateOrder(UIOrder order) throws DelistedException {
        try {
            factory.getOrderDao().update(Proxy.createFromUIOrder(order));
        } catch (DataAccessException e) {
            throw new DelistedException(e.getMessage());
        }
    }

    @Override
    public void addNewObjectToReferenceBook(UIService obj) throws DelistedException {
        try {
            factory.getServiceDao().create(Proxy.createFromUIService(obj));
        } catch (Exception e) {
            throw new DelistedException(e.getMessage());
        }
    }

    @Override
    public void addNewObjectToReferenceBook(UIEquipment obj) throws DelistedException {
        try {
            factory.getEquipmentDao().create(Proxy.createFromUIEquipment(obj));
        } catch (Exception e) {
            throw new DelistedException(e.getMessage());
        }
    }

    @Override
    public void deleteObjectsFromEquipmentRB(List<UIEquipment> objs) throws DelistedException {
        List<Equipment> equipmentList = new ArrayList<Equipment>();
        for (UIEquipment uiEquipment : objs)
            equipmentList.add(Proxy.createFromUIEquipment(uiEquipment));
        try {
            ((EquipmentDao) factory.getEquipmentDao()).deleteList(equipmentList);
        } catch (Exception e) {
            throw new DelistedException(e.getMessage());
        }
    }

    @Override
    public void deleteObjectsFromServiceRB(List<UIService> objs) throws DelistedException {
        List<Service> serviceList = new ArrayList<Service>();
        for (UIService uiService : objs)
            serviceList.add(Proxy.createFromUIService(uiService));
        try {
            ((ServiceDao) factory.getServiceDao()).deleteList(serviceList);
        } catch (Exception e) {
            throw new DelistedException(e.getMessage());
        }
    }

    @Override
    public void deleteOrder(UIOrder order) throws DelistedException {
        try {
            factory.getOrderDao().delete(Proxy.createFromUIOrder(order));
        } catch (DataAccessException e) {
            throw new DelistedException(e.getMessage());
        }
    }

    @Override
    public void deleteCustomer(UICustomer customer) throws DelistedException {
        try {
            factory.getCustomerDao().delete(Proxy.createFromUICustomer(customer));
        } catch (DataAccessException e) {
            throw new DelistedException(e.getMessage());
        }
    }

    @Override
    public List<UIHistory> getHistoryByOrderId(int id) throws DelistedException {
        List<UIHistory> uiHistories = new ArrayList<UIHistory>();
        for (History history : ((HistoryDao) factory.getHistoryDao()).getHistoryByOrderId(id)) {
            uiHistories.add(Proxy.createFromHistory(history));
        }
        return uiHistories;
    }

    @Override
    public void addHistory(UIHistory history) throws DelistedException {
        try {
            factory.getHistoryDao().create(Proxy.createFromUIHistory(history));
        } catch (DataAccessException e) {
            throw new DelistedException(e.getMessage());
        }
    }

    @Override
    public void addOrderServEquipList(List<UIOrderServEquip> orderServEquipList) throws DelistedException {
        List<OrderServEquip> orderServEquips = new ArrayList<OrderServEquip>();
        for (UIOrderServEquip object : orderServEquipList) {
            orderServEquips.add(Proxy.createFromUIOrderServEquip(object));
        }
        try {
            ((OrderServEquipDao) factory.getOrderServEquipDao()).addOrderServEquipList(orderServEquips);
        } catch (DataAccessException e) {
            throw new DelistedException(e.getMessage());
        }
    }

    @Override
    public void deleteOrderServEquipList(List<UIOrderServEquip> orderServEquipList) throws DelistedException {
        List<OrderServEquip> orderServEquips = new ArrayList<OrderServEquip>();
        for (UIOrderServEquip object : orderServEquipList) {
            orderServEquips.add(Proxy.createFromUIOrderServEquip(object));
        }
        try {
            ((OrderServEquipDao) factory.getOrderServEquipDao()).deleteOrderServEquipList(orderServEquips);
        } catch (DataAccessException e) {
            throw new DelistedException(e.getMessage());
        }
    }

    @Override
    public List<UIEquipment> deleteParentEquipmentList(List<UIEquipment> equipments) throws DelistedException {
        List<UIEquipment> couldNotBeDeleted = new ArrayList<UIEquipment>();
        for (UIEquipment equipment : equipments) {
            try {
                if (((EquipmentDao) factory.getEquipmentDao()).canBeParentDeleted(Proxy.createFromUIEquipment(equipment))) {
                    factory.getEquipmentDao().delete(Proxy.createFromUIEquipment(equipment));
                } else {
                    couldNotBeDeleted.add(equipment);
                }
            } catch (DataAccessException e) {
                throw new DelistedException(e.getMessage());
            }
        }
        return couldNotBeDeleted;
    }

    @Override
    public List<UIEquipment> deleteChildEquipmentList(List<UIEquipment> equipments) throws DelistedException {
        List<UIEquipment> couldNotBeDeleted = new ArrayList<UIEquipment>();
        for (UIEquipment equipment : equipments) {
            try {
                if (((EquipmentDao) factory.getEquipmentDao()).canBeChildDeleted(Proxy.createFromUIEquipment(equipment))) {
                    factory.getEquipmentDao().delete(Proxy.createFromUIEquipment(equipment));
                } else {
                    couldNotBeDeleted.add(equipment);
                }
            } catch (DataAccessException e) {
                throw new DelistedException(e.getMessage());
            }
        }
        return couldNotBeDeleted;
    }

    @Override
    public List<UIService> deleteParentServiceList(List<UIService> services) throws DelistedException {
        List<UIService> couldNotBeDeleted = new ArrayList<UIService>();
        for (UIService service : services) {
            try {
                if (((ServiceDao) factory.getServiceDao()).canBeParentDeleted(Proxy.createFromUIService(service))) {
                    factory.getServiceDao().delete(Proxy.createFromUIService(service));
                } else {
                    couldNotBeDeleted.add(service);
                }
            } catch (DataAccessException e) {
                throw new DelistedException(e.getMessage());
            }
        }
        return couldNotBeDeleted;
    }

    @Override
    public List<UIService> deleteChildServiceList(List<UIService> services) throws DelistedException {
        List<UIService> couldNotBeDeleted = new ArrayList<UIService>();
        for (UIService service : services) {
            try {
                if (((ServiceDao) factory.getServiceDao()).canBeChildDeleted(Proxy.createFromUIService(service))) {
                    factory.getServiceDao().delete(Proxy.createFromUIService(service));
                } else {
                    couldNotBeDeleted.add(service);
                }
            } catch (DataAccessException e) {
                throw new DelistedException(e.getMessage());
            }
        }
        return couldNotBeDeleted;
    }

    @Override
    public Map<UIOrder, Boolean> validateOrderSchedule(List<UIOrder> uiOrders) throws DelistedException {
        Map<Integer, Boolean> orderStatus;
        Map<UIOrder, Boolean> listOfOrders = new HashMap<UIOrder, Boolean>();
        List<Order> orders = new ArrayList<Order>();
        for (UIOrder uiOrder : uiOrders)
            orders.add(Proxy.createFromUIOrder(uiOrder));
        try {
            orderStatus = ((OrderDao) factory.getOrderDao()).validateOrderSchedule(orders);
            for (Integer id : orderStatus.keySet()) {
                listOfOrders.put(Proxy.createFromOrder(factory.getOrderDao().getById(id)), orderStatus.get(id));
            }
        } catch (DataAccessException e) {
            throw new DelistedException(e.getMessage());
        }

        return listOfOrders;
    }

    @Override
    public void updateOrderList(List<UIOrder> orderList) throws DelistedException {
        List<Order> orders = new ArrayList<Order>();
        for (UIOrder order : orderList)
            orders.add(Proxy.createFromUIOrder(order));
        try {
            ((OrderDao) factory.getOrderDao()).updateList(orders);
        } catch (DataAccessException e) {
            throw new DelistedException(e.getMessage());
        }
    }

    @Override
    public List<UIEquipment> getEquipmentByServicesList(List<UIService> services) throws DelistedException {
        List<UIEquipment> equipments = new ArrayList<UIEquipment>();
        List<Service> serviceList = new ArrayList<Service>();
        for (UIService service : services) {
            serviceList.add(Proxy.createFromUIService(service));
        }
        for (Equipment equipment : ((EquipmentDao) factory.getEquipmentDao()).getEquipmentByServicesList(serviceList)) {
            equipments.add(Proxy.createFromEquipment(equipment));
        }
        return equipments;
    }

    @Override
    public UIEquipment getEquipmentById(int id) throws DelistedException {
        UIEquipment equipment;
        try {
            equipment = Proxy.createFromEquipment(factory.getEquipmentDao().getById(id));
        } catch (DataAccessException e) {
            throw new DelistedException(e.getMessage());
        }
        return equipment;
    }

    @Override
    public UIService getServiceById(int id) throws DelistedException {
        UIService service;
        try {
            service = Proxy.createFromService(factory.getServiceDao().getById(id));
        } catch (DataAccessException e) {
            throw new DelistedException(e.getMessage());
        }
        return service;
    }

    @Override
    public void addRefsList(List<UIRefs> uiRefsList) throws DelistedException {
        List<Refs> refsList = new ArrayList<Refs>();
        for (UIRefs uiRefs : uiRefsList)
            refsList.add(Proxy.createFromUIRefs(uiRefs));
        try {
            ((RefsDao) factory.getRefsDao()).addList(refsList);
        } catch (DataAccessException e) {
            throw new DelistedException(e.getMessage());
        }
    }

    @Override
    public void deleteRefsList(List<UIRefs> uiRefsList) throws DelistedException {
        List<Refs> refsList = new ArrayList<Refs>();
        for (UIRefs uiRefs : uiRefsList)
            refsList.add(Proxy.createFromUIRefs(uiRefs));
        try {
            ((RefsDao) factory.getRefsDao()).deleteList(refsList);
        } catch (DataAccessException e) {
            throw new DelistedException(e.getMessage());
        }
    }
}
